<template>
  <div class="ie-markdown">
    <div class="ie-markdown--commands" v-if="editor">
      <n-space>
        <n-button
          :class="{ 'is-active': editor.isActive('bold') }"
          @click="editor.chain().focus().toggleBold().run()"
          text
        >
          <template #icon>
            <n-icon><FormatBoldOutlined /></n-icon>
          </template>
        </n-button>
        <n-button
          :class="{ 'is-active': editor.isActive('italic') }"
          @click="editor.chain().focus().toggleItalic().run()"
          text
        >
          <template #icon>
            <n-icon><FormatItalicOutlined /></n-icon>
          </template>
        </n-button>
        <n-button
          :class="{ 'is-active': editor.isActive('strike') }"
          @click="editor.chain().focus().toggleStrike().run()"
          text
        >
          <template #icon>
            <n-icon><FormatStrikethroughOutlined /></n-icon>
          </template>
        </n-button>
        <n-button
          :class="{ 'is-active': editor.isActive('code') }"
          @click="editor.chain().focus().toggleCode().run()"
          text
        >
          <template #icon>
            <n-icon><CodeOutlined /></n-icon>
          </template>
        </n-button>
        <n-button
          :class="{ 'is-active': editor.isActive('highlight') }"
          @click="editor.chain().focus().toggleHighlight().run()"
          text
        >
          <template #icon>
            <n-icon><HighlightAltOutlined /></n-icon>
          </template>
        </n-button>
        <n-divider vertical />
        <n-button
          :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }"
          @click="editor.chain().focus().toggleHeading({ level: 1 }).run()"
          text
        >
          <template #icon>
            <n-icon size="16"><Heading /><sub>1</sub></n-icon>
          </template>
        </n-button>
        <n-button
          :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }"
          @click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
          text
        >
          <template #icon>
            <n-icon size="16"><Heading /><sub>2</sub></n-icon>
          </template>
        </n-button>
        <n-button
          :class="{ 'is-active': editor.isActive('paragraph') }"
          @click="editor.chain().focus().setParagraph().run()"
          text
        >
          <template #icon>
            <n-icon><TextFieldsOutlined /></n-icon>
          </template>
        </n-button>
        <n-button
          :class="{ 'is-active': editor.isActive('bulletList') }"
          @click="editor.chain().focus().toggleBulletList().run()"
          text
        >
          <template #icon>
            <n-icon><FormatListBulletedFilled /></n-icon>
          </template>
        </n-button>
        <n-button
          :class="{ 'is-active': editor.isActive('orderedList') }"
          @click="editor.chain().focus().toggleOrderedList().run()"
          text
        >
          <template #icon>
            <n-icon><FormatListNumberedFilled /></n-icon>
          </template>
        </n-button>
        <n-divider vertical />
        <n-upload
          action="/api/upload"
          @finish="onUploadFinish"
          accept="image/*"
          :headers="getHeaders"
          :show-file-list="false"
        >
          <n-button text>
            <template #icon>
              <n-icon><ImageOutlined /></n-icon>
            </template>
          </n-button>
        </n-upload>
        <n-divider vertical />
        <n-button
          @click="editor.chain().focus().undo().run()"
          text
        >
          <template #icon>
            <n-icon><UndoFilled /></n-icon>
          </template>
        </n-button>
        <n-button
          @click="editor.chain().focus().redo().run()"
          text
        >
          <template #icon>
            <n-icon><RedoFilled /></n-icon>
          </template>
        </n-button>
      </n-space>
    </div>
    <editor-content
      class="ie-markdown--content"
      :editor="editor"
    />
  </div>
</template>

<script setup>
import { watch, onBeforeUnmount } from 'vue'
import { useEditor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
import TextAlign from '@tiptap/extension-text-align'
import Highlight from '@tiptap/extension-highlight'
import Image from '@tiptap/extension-image'

import FormatBoldOutlined from '@vicons/material/FormatBoldOutlined'
import FormatItalicOutlined from '@vicons/material/FormatItalicOutlined'
import FormatStrikethroughOutlined from '@vicons/material/FormatStrikethroughOutlined'
import CodeOutlined from '@vicons/material/CodeOutlined'
import HighlightAltOutlined from '@vicons/material/HighlightAltOutlined'
import Heading from '@vicons/tabler/Heading'
import TextFieldsOutlined from '@vicons/material/TextFieldsOutlined'
import FormatListBulletedFilled from '@vicons/material/FormatListBulletedFilled'
import FormatListNumberedFilled from '@vicons/material/FormatListNumberedFilled'
import ImageOutlined from '@vicons/material/ImageOutlined'
import UndoFilled from '@vicons/material/UndoFilled'
import RedoFilled from '@vicons/material/RedoFilled'

import { getHeaders } from '/@/api'

const props = defineProps({
  value: {
    type: String,
    default: ''
  }
})
const emit = defineEmits([
  'update:value'
])

const editor = useEditor({
  content: '',
  extensions: [
    StarterKit,
    TextAlign,
    Highlight,
    Image
  ],
  onUpdate: () => {
    emit('update:value', editor.value.getHTML())
  }
})

watch(
  () => props.value,
  v => {
  if (editor.value.getHTML() === v) {
    return
  }

  editor.value.commands.setContent(props.value, false)
})

onBeforeUnmount(() => {
  editor && editor.value.destroy()
})

function onUploadFinish({ event }) {
  try {
    event = JSON.parse(event.target.response)
  } catch (err) {}

  if (event.code === 0) {
    const url = event.data.filepath

    if (url && editor.value) {
      editor.value.chain().focus().setImage({ src: url }).run()
    }
  }
}
</script>

<style lang="less">
.ie-markdown {
  width: 100%;

  &--commands {
    border-bottom: 1px solid rgb(224, 224, 230);
    padding: 0 8px;

    .n-button {
      padding: 8px 0;
    }

    .n-divider {
      height: 18px;
      margin-top: 8px;
      margin-left: 0;
      margin-right: 0;
    }

    sub {
      font-size: 10px;
      margin-left: -4px;
      position: relative;
      top: -6px;
    }
  }

  &--content {
    padding: 8px 12px;
    min-height: 300px;

    & > div {

      &:focus-visible {
        outline: 0;
      }
    }
  }
}
</style>

<style lang="less">
.ie-markdown--content {
  line-height: 1.8;
  padding-top: 1.5em;
  padding-bottom: 2em;

  a {
    text-decoration: none;

    &:hover {
      border-bottom: 1px solid;
    }
  }

  abbr {
    border-bottom: 1px dotted;
    cursor: help;
  }

  cite {
    font-style: italic;
  }

  hr {
    background: #e6e6e6;
    border: none;
    display: block;
    height: 1px;
    margin-bottom: 1.4em;
    margin-top: 1.4em;
  }

  img {
    vertical-align: text-bottom;
    max-width: 100%;
  }

  ins {
    background-color: lime;
    text-decoration: none;
  }

  mark {
    background-color: #ff0;
  }

  small {
    font-size: 0.8em;
  }

  strong {
    font-weight: 700;
  }

  sub,
  sup {
    font-size: 0.8em;
  }

  sub {
    vertical-align: sub;
  }

  sup {
    vertical-align: super;
  }

  p,
  dl,
  ol,
  ul,
  blockquote,
  pre,
  table {
    margin-bottom: 1.4em;
    font-size: 16px;
    color: #565656;

    &:last-child {
      margin-bottom: 0;
    }
  }

  p:empty {
    display: none;
  }

  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    font-weight: 700;
    line-height: 1.2;
    color: #2b2b2b;

    &:first-child {
      margin-top: 0;
    }
  }

  h1 {
    font-size: 2.4em;
    margin-bottom: 0.58333em;
    margin-top: 0.58333em;
    line-height: 1;
  }
  h2 {
    font-size: 1.6em;
    margin-bottom: 0.875em;
    margin-top: 1.75em;
    line-height: 1.1;
  }
  h3 {
    font-size: 1.3em;
    margin-bottom: 1.07692em;
    margin-top: 1.07692em;
  }
  h4 {
    font-size: 1.2em;
    margin-bottom: 1.16667em;
    margin-top: 1.16667em;
  }
  h5 {
    font-size: 1.1em;
    margin-bottom: 1.27273em;
    margin-top: 1.27273em;
  }
  h6 {
    font-size: 1em;
    margin-bottom: 1.4em;
    margin-top: 1.4em;
  }

  dd {
    margin-left: 1.4em;
  }

  ol,
  ul {
    list-style-position: outside;
    // margin-left: 1.4em;
    padding-left: 1.4em;
  }

  blockquote {
    border-left: 4px solid #e6e6e6;
    padding: 0.6em 1.2em;

    p {
      margin-bottom: 0;
    }
  }

  code,
  kbd,
  samp,
  pre {
    font-smoothing: auto;
    background-color: #f2f2f2;
    color: #333;
    font-size: 0.9em;
    border-radius: 3px;
    line-height: 1.77778;
    padding: 0.1em 0.4em 0.2em;
    vertical-align: baseline;
  }

  pre {
    overflow: auto;
    padding: 1em 1.2em;
    
    code {
      background: none;
      font-size: 1em;
      line-height: 1em;
    }
  }

  figure {
    margin-bottom: 2.8em;
    text-align: center;

    &:first-child {
      margin-top: 0;
    }

    &:last-child {
      margin-bottom: 0;
    }
  }

  figcaption {
    font-size: 0.8em;
    margin-top: 0.875em;
  }

  table {
    width: 100%;

    pre {
      white-space: pre-wrap;
    }
  }

  th,
  td {
    font-size: 1em;
    padding: 0.7em;
    border: 1px solid #e6e6e6;
    line-height: 1.4;
  }

  thead tr,
  tfoot tr {
    background-color: #fafcfc;
  }

  thead,
  tfoot {
    th,
    td {
      font-size: 0.9em;
      padding: 0.77778em;

      code {
        background-color: #fff;
      }
    }
  }

  tbody tr {
    background-color: #fff;
  }
}
</style>
